/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/math/vector/Sse
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AESimdFloat32_Sse.inl
// Author:		Gianluca Belardelli
// Date:		22/01/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESIMDFLOAT32_SSE_INL_
#define _AESIMDFLOAT32_SSE_INL_

AE_FORCEINLINE AESimdFloat32::AESimdFloat32(const AEFLOAT32 &fValue )
{
	//	__m128 _mm_set1_ps(float w );
	//		Sets the four single-precision, floating-point values to w.
	//		r0 := r1 := r2 := r3 := w 
	m_fReal = _mm_set1_ps( fValue );
}

AE_FORCEINLINE AESimdFloat32::operator AEFLOAT32( void ) const
{
	//	float _mm_cvtss_f32( __m128 a );
	//		Extracts the lower order floating point value from the parameter.
	//		r := a0
	return _mm_cvtss_f32( m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetFromFloat( const AEFLOAT32 &fValue )
{
	//	__m128 _mm_load_ss(float * p ); MOVSS
	//		Loads an single-precision, floating-point value into the low word and clears the upper three words.
	//		r0 := *p 
	//		r1 := 0.0 ; r2 := 0.0 ; r3 := 0.0
	//	__m128 _mm_shuffle_ps(__m128 a , __m128 b , int i ); SHUFPS
	//		Selects four specific single-precision, floating-point values from a and b, based on the mask i.
	__m128 fx = _mm_load_ss( &fValue );
	m_fReal = _mm_shuffle_ps( fx,fx,_MM_SHUFFLE( 0,0,0,0 ) );
}

AE_FORCEINLINE void AESimdFloat32::SetFromFloat( const AEDOUBLE64 &dValue )
{
	//	__m128d _mm_load_sd (double *p); MOVSD
	//		Loads a double-precision, floating-point value.
	//		r0 := *p 
	//		r1 := 0.0
	//	__m128 _mm_cvtpd_ps (__m128d a); CVTPD2PS
	//		Converts the two double-precision, floating-point values of a to single-precision, floating-point values.
	//		r0 := (float) a0
	//		r1 := (float) a1
	//		r2 := 0.0 ; r3 := 0.0
	//	__m128 _mm_shuffle_ps(__m128 a , __m128 b , int i ); SHUFPS
	//		Selects four specific single-precision, floating-point values from a and b, based on the mask i.
	__m128d d = _mm_load_sd( &dValue );
	__m128 f = _mm_cvtpd_ps( d );
	m_fReal = _mm_shuffle_ps( f, f, _MM_SHUFFLE( 0, 0, 0, 0 ) );
}

AE_FORCEINLINE void AESimdFloat32::SetFromUint16( const AEUINT16 &uiValue )
{
	int i = uiValue;
	SetFromInt32(i);
}

AE_FORCEINLINE void AESimdFloat32::SetFromUint8( const AEUINT8 &uiValue )
{
	int i = uiValue;
	SetFromInt32(i);
}

AE_FORCEINLINE void AESimdFloat32::SetFromInt32( const AEINT32 &nValue )
{
	//	__m128 _mm_cvtsi32_ss(__m128 a , int b ); CVTSI2SS
	//		Converts the 32-bit integer value b to an single-precision, floating-point value;
	//		the upper three single-precision, floating-point values are passed through from a.
	//		r0 := (float)b
	//		r1 := a1 ; r2 := a2 ; r3 := a3
	//	__m128 _mm_setzero_ps(void);
	//		Clears the four single-precision, floating-point values.
	//		r0 := r1 := r2 := r3 := 0.0 
	//	__m128 _mm_shuffle_ps(__m128 a , __m128 b , int i ); SHUFPS
	//		Selects four specific single-precision, floating-point values from a and b, based on the mask i.
	__m128 ix = _mm_cvtsi32_ss( _mm_setzero_ps(), nValue );
	m_fReal = _mm_shuffle_ps( ix, ix, _MM_SHUFFLE( 0, 0, 0, 0 ) );
}

AE_FORCEINLINE void AESimdFloat32::SetZero( void )
{
	//	__m128 _mm_setzero_ps(void);
	//		Clears the four single-precision, floating-point values.
	//		r0 := r1 := r2 := r3 := 0.0 
	m_fReal = _mm_setzero_ps();
}

AE_FORCEINLINE AEFLOAT32 AESimdFloat32::GetReal( void ) const
{
	//	float _mm_cvtss_f32( __m128 a );
	//		Extracts the lower order floating point value from the parameter.
	//		r := a0
	return _mm_cvtss_f32( m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::StoreSaturateInt32( AEINT32 *lpRes ) const
{
	//	int _mm_cvtsi128_si32 (__m128i a); MOVD
	//		Moves the least significant 32 bits of a to a 32-bit integer.
	//		r := a0
	//	__m128i _mm_cvttps_epi32 (__m128 a); CVTTPS2DQ
	//		Converts the four single-precision, floating-point values of a to signed 32-bit integer values using truncate.
	//		r0 := (int) a0
	//		r1 := (int) a1
	//		r2 := (int) a2
	//		r3 := (int) a3
	*lpRes = _mm_cvtsi128_si32( _mm_cvttps_epi32( m_fReal ) );
}

AE_FORCEINLINE void AESimdFloat32::StoreSaturateUint16( AEUINT16 *lpRes ) const
{
	//	__m128 _mm_max_ps(__m128 a , __m128 b ); MAXPS
	//		Computes the maximums of the four single-precision, floating-point values of a and b.
	//		r0 := max(a0, b0)
	//		r1 := max(a1, b1)
	//		r2 := max(a2, b2)
	//		r3 := max(a3, b3) 
	//	__m128 _mm_min_ps(__m128 a , __m128 b ); MINPS
	//		Computes the minima of the four single-precision, floating-point values of a and b.
	//		r0 := min(a0, b0)
	//		r1 := min(a1, b1)
	//		r2 := min(a2, b2)
	//		r3 := min(a3, b3) 
	//	__m128 _mm_set1_ps(float w );
	//		Sets the four single-precision, floating-point values to w.
	//		r0 := r1 := r2 := r3 := w 
	//	int _mm_cvtsi128_si32 (__m128i a); MOVD
	//		Moves the least significant 32 bits of a to a 32-bit integer.
	//		r := a0
	//	__m128i _mm_cvttps_epi32 (__m128 a); CVTTPS2DQ
	//		Converts the four single-precision, floating-point values of a to signed 32-bit integer values using truncate.
	//		r0 := (int) a0
	//		r1 := (int) a1
	//		r2 := (int) a2
	//		r3 := (int) a3
	AESingleFloat32 fClamped = _mm_max_ps( m_fReal, _mm_setzero_ps() );	
	fClamped = _mm_min_ps( fClamped, _mm_set1_ps( 65535.0f ) );
	*lpRes = AEUINT16 (_mm_cvtsi128_si32( _mm_cvttps_epi32( fClamped ) ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator-( void ) const
{
	// 	__m128 _mm_sub_ps(__m128 a , __m128 b ); SUBPS
	//		Subtracts the four single-precision, floating-point values of a and b.
	//		r0 := a0 - b0
	//		r1 := a1 - b1
	//		r2 := a2 - b2
	//		r3 := a3 - b3
	//	__m128 _mm_setzero_ps(void);
	//		Clears the four single-precision, floating-point values.
	//		r0 := r1 := r2 := r3 := 0.0 
	return AESimdFloat32::Convert( _mm_sub_ps( _mm_setzero_ps(), m_fReal ) );
}

AE_FORCEINLINE void AESimdFloat32::SetMax( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	//	__m128 _mm_max_ps(__m128 a , __m128 b ); MAXPS
	//		Computes the maximums of the four single-precision, floating-point values of a and b.
	//		r0 := max(a0, b0)
	//		r1 := max(a1, b1)
	//		r2 := max(a2, b2)
	//		r3 := max(a3, b3) 
	m_fReal = _mm_max_ps( fParam1.m_fReal, fParam2.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetMin( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	//	__m128 _mm_min_ps(__m128 a , __m128 b ); MINPS
	//		Computes the minima of the four single-precision, floating-point values of a and b.
	//		r0 := min(a0, b0)
	//		r1 := min(a1, b1)
	//		r2 := min(a2, b2)
	//		r3 := min(a3, b3) 
	m_fReal = _mm_min_ps( fParam1.m_fReal, fParam2.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetAbs( AESimdFloat32ConstRef fParam )
{
	m_fReal = AEMathSSE::QuadFabs( fParam.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetFloor( AESimdFloat32ConstRef fParam )
{
	m_fReal = AEMathSSE::QuadFloor( fParam.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetMod( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	m_fReal = AEMathSSE::QuadMod( fParam1.m_fReal, fParam2.m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::SetFlipSign( AESimdFloat32ConstRef fParam, AESimdFloat32ConstRef fSign )
{
	//	__m128i _mm_slli_epi32 (__m128i a, int count); PSLLD
	//		Shifts the 4 signed or unsigned 32-bit integers in a left by count bits while shifting in zeros.
	//		r0 := a0 << count
	//		r1 := a1 << count
	//		r2 := a2 << count
	//		r3 := a3 << count
	//	__m128i _mm_srli_epi32 (__m128i a, int count); PSRLD
	//		Shifts the 4 signed or unsigned 32-bit integers in a right by count bits while shifting in zeros.
	//		r0 := srl(a0, count)
	//		r1 := srl(a1, count)
	//		r2 := srl(a2, count)
	//		r3 := srl(a3, count)
	//	__m128i _mm_castps_si128(__m128 a);
	//		Applies a type cast to reinterpret four 32-bit floating point values passed in 
	//		as a 128-bit parameter as packed 32-bit integers.
	//		r := a
	//	__m128 _mm_xor_ps(__m128 a , __m128 b ); XORPS
	//		Computes bitwise EXOR (exclusive-or) of the four single-precision, floating-point values of a and b.
	//		r0 := a0 ^ b0
	//		r1 := a1 ^ b1
	//		r2 := a2 ^ b2
	//		r3 := a3 ^ b3
	//	__m128i _mm_castsi128_ps(__m128i a);
	//		Applies a type cast to reinterpret four 32-bit integers passed in 
	//		as a 128-bit parameter as packed 32-bit floating point values.
	//		r := a
	const __m128i mask = _mm_slli_epi32( _mm_srli_epi32( _mm_castps_si128( fSign.m_fReal ), 31 ), 31 );
	m_fReal = _mm_xor_ps( fParam.m_fReal, _mm_castsi128_ps( mask ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator+ ( AESimdFloat32ConstRef fParam ) const
{
	// 	__m128 _mm_add_ps(__m128 a , __m128 b ); ADDPS
	//		Adds the four single-precision, floating-point values of a and b.
	//		r0 := a0 + b0
	//		r1 := a1 + b1
	//		r2 := a2 + b2
	//		r3 := a3 + b3
	return AESimdFloat32::Convert( _mm_add_ps( m_fReal, fParam.m_fReal ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator- ( AESimdFloat32ConstRef fParam ) const
{
	// 	__m128 _mm_sub_ps(__m128 a , __m128 b ); SUBPS
	//		Subtracts the four single-precision, floating-point values of a and b.
	//		r0 := a0 - b0
	//		r1 := a1 - b1
	//		r2 := a2 - b2
	//		r3 := a3 - b3
	return AESimdFloat32::Convert( _mm_sub_ps( m_fReal, fParam.m_fReal ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator* ( AESimdFloat32ConstRef fParam ) const
{
	//	__m128 _mm_mul_ps(__m128 a , __m128 b ); MULPS
	//		Multiplies the four single-precision, floating-point values of a and b.
	//		r0 := a0 * b0
	//		r1 := a1 * b1
	//		r2 := a2 * b2
	//		r3 := a3 * b3
	return AESimdFloat32::Convert( _mm_mul_ps( m_fReal, fParam.m_fReal ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::operator/ ( AESimdFloat32ConstRef fParam ) const
{
	AESimdFloat32 fResult;
	fResult.SetDiv( *this, fParam );
	return fResult;
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathIoMode A>
	struct unrollf_store
	{ 
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};

	template <AEMathIoMode A>
	struct unrollf_store_D
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};

	template <>
	struct unrollf_store<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			_mm_store_ss( lpAddr, fSelf );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			__m128d d = _mm_cvtps_pd( fSelf );
			_mm_store_sd( lpAddr, d );
		}
	};

	template <>
	struct unrollf_store<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			//HK_MATH_ASSERT(0x64211c2f, ( ((AEUINT32)lpAddr) & (sizeof(AEFLOAT32)-1) ) == 0, "pointer must be aligned to native size of AEFLOAT32.");
			unrollf_store<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			//HK_MATH_ASSERT(0x64211c2f, ( ((AEUINT32)lpAddr) & (sizeof(AEDOUBLE64)-1) ) == 0, "pointer must be aligned to native size of AEDOUBLE64.");
			unrollf_store_D<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			unrollf_store<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			unrollf_store_D<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEFLOAT32 *lpAddr )
		{
			unrollf_store<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};

	template <>
	struct unrollf_store_D<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply(const AESingleFloat32 &fSelf, AEDOUBLE64 *lpAddr )
		{
			unrollf_store_D<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
} // namespace 

template <int N, AEMathIoMode A, AEMathRoundingMode R>
AE_FORCEINLINE void AESimdFloat32::Store( AEFLOAT32 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A, AEMathRoundingMode R>
AE_FORCEINLINE void AESimdFloat32::Store( AEDOUBLE64 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store_D<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Store( AEFLOAT32 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Store( AEDOUBLE64 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store_D<A>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Store( AEFLOAT32 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Store( AEDOUBLE64 *lpAddr ) const
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_store_D<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathIoMode A>
	struct unrollf_load
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <AEMathIoMode A>
	struct unrollf_load_D
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			fSelf = _mm_load1_ps( lpAddr );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_BYTE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			__m128d a = _mm_load_sd( lpAddr );
			__m128 f = _mm_cvtpd_ps( a );
			fSelf = _mm_shuffle_ps( f, f, _MM_SHUFFLE( 0, 0, 0, 0 ) );
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			//HK_MATH_ASSERT(0x64211c2f, ( ((AEUINT32)lpAddr) & (sizeof(AEFLOAT32)-1) ) == 0, "pointer must be aligned to native size of AEFLOAT32.");
			unrollf_load<AE_IO_BYTE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_NATIVE_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			//HK_MATH_ASSERT(0x64211c2f, ( ((AEUINT32)lpAddr) & (sizeof(AEDOUBLE64)-1) ) == 0, "pointer must be aligned to native size of AEDOUBLE64.");
			unrollf_load_D<AE_IO_BYTE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			unrollf_load<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_SIMD_ALIGNED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			unrollf_load_D<AE_IO_NATIVE_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEFLOAT32 *lpAddr )
		{
			unrollf_load<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
	
	template <>
	struct unrollf_load_D<AE_IO_NOT_CACHED>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, const AEDOUBLE64 *lpAddr )
		{
			unrollf_load_D<AE_IO_SIMD_ALIGNED>::Apply( fSelf, lpAddr );
		}
	};
} // namespace 

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Load( const AEFLOAT32 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load<A>::Apply( m_fReal, lpAddr );
}

template <int N, AEMathIoMode A>
AE_FORCEINLINE void AESimdFloat32::Load( const AEDOUBLE64 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load_D<A>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Load( const AEFLOAT32 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

template <int N>
AE_FORCEINLINE void AESimdFloat32::Load( const AEDOUBLE64 *lpAddr )
{
	AE_SIMDFLOAT_DIMENSION_CHECK;
	AESimdReal_AdvancedInterface::unrollf_load_D<AE_IO_SIMD_ALIGNED>::Apply( m_fReal, lpAddr );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S>
	struct unrollf_sqrt
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
			return _mm_setzero_ps();
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrt<A, AE_SQRT_IGNORE>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: return _mm_mul_ps( fSelf.m_fReal, AEMath::QuadReciprocalSquareRoot( fSelf.m_fReal ) ); break;
				case AE_ACC_12_BIT: return _mm_mul_ps( fSelf.m_fReal,_mm_rsqrt_ps( fSelf.m_fReal ) ); break;
				default:            return _mm_sqrt_ps( fSelf.m_fReal ); break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrt<A, AE_SQRT_SET_ZERO>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			const AESingleFloat32 equalsZero = _mm_cmple_ps( fSelf.m_fReal, _mm_setzero_ps() );
			const AESingleFloat32 e = unrollf_sqrt<A, AE_SQRT_IGNORE>::Apply( fSelf );
			return _mm_andnot_ps( equalsZero, e );
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathNegSqrtMode S> 
AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::Sqrt( void ) const
{
	return AESimdFloat32::Convert( AESimdReal_AdvancedInterface::unrollf_sqrt<A,S>::Apply( *this ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::Sqrt( void ) const
{
	return AESimdFloat32::Convert( AESimdReal_AdvancedInterface::unrollf_sqrt<AE_ACC_23_BIT,AE_SQRT_SET_ZERO>::Apply( *this ) );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsSignBitSet( void ) const
{
	return _mm_movemask_ps( m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsSignBitClear( void ) const
{
	return !_mm_movemask_ps( m_fReal ); 
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLess( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomilt_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLessEqual( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomile_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreater( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomigt_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreaterEqual( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomige_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsEqual( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomieq_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsNotEqual( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomineq_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLessZero( void ) const
{
	return _mm_ucomilt_ss( m_fReal, _mm_setzero_ps() );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsLessEqualZero( void ) const
{
	return _mm_ucomile_ss( m_fReal, _mm_setzero_ps() );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreaterZero( void ) const
{
	return _mm_ucomigt_ss( m_fReal, _mm_setzero_ps() );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsGreaterEqualZero( void ) const
{
	return _mm_ucomige_ss( m_fReal, _mm_setzero_ps() );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsEqualZero( void ) const
{
	return _mm_ucomieq_ss( m_fReal, _mm_setzero_ps() );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsNotEqualZero( void ) const
{
	return _mm_ucomineq_ss( m_fReal, _mm_setzero_ps() );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::IsOk( void ) const
{
	const AESingleFloat32 nanMask = _mm_cmpord_ps( m_fReal, _mm_setzero_ps() );
	return _mm_movemask_ps( nanMask );
}

AE_FORCEINLINE void AESimdFloat32::SetFlipSign( AESimdFloat32ConstRef fParam, AEVector4fConstRefCompParam vcMask )
{
	AEASSERT_MSG( vcMask.AllAreSet() || ( vcMask.GetMask() == AEVector4ComparisonMask::MASK_NONE), "illegal compare mask");
	const __m128i maskS = _mm_slli_epi32( _mm_srli_epi32( _mm_castps_si128( vcMask.m_mMask ), 31 ), 31 );
	m_fReal = _mm_xor_ps( fParam.m_fReal, _mm_castsi128_ps( maskS ) );
}

AE_FORCEINLINE void AESimdFloat32::SetSelect( AEVector4fConstRefCompParam vcComp, AESimdFloat32ConstRef fTrueValue, AESimdFloat32ConstRef fFalseValue  )
{
	AEASSERT_MSG( vcComp.AllAreSet() || ( vcComp.GetMask() == AEVector4ComparisonMask::MASK_NONE), "illegal compare mask");
#if AE_SSE_VERSION >= 0x41
	m_fReal = _mm_blendv_ps( fFalseValue.m_fReal, fTrueValue.m_fReal, vcComp.m_mMask );
#else
	m_fReal = _mm_or_ps( _mm_and_ps( vcComp.m_mMask, fTrueValue.m_fReal ), _mm_andnot_ps( vcComp.m_mMask, fFalseValue.m_fReal ) );
#endif

}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator< ( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomilt_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator<= ( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomile_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator> ( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomigt_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator>= ( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomige_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator== ( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomieq_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE AEBOOL32 AESimdFloat32::operator!= ( AESimdFloat32ConstRef fValue ) const
{
	return _mm_ucomineq_ss( m_fReal, fValue.m_fReal );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpL( AESimdFloat32ConstRef fValue ) const
{
	return AEVector4fComparison::Convert( _mm_cmplt_ps( m_fReal, fValue.m_fReal ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpLE( AESimdFloat32ConstRef fValue ) const
{
	return AEVector4fComparison::Convert( _mm_cmple_ps( m_fReal, fValue.m_fReal ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpG( AESimdFloat32ConstRef fValue ) const
{
	return AEVector4fComparison::Convert( _mm_cmpgt_ps( m_fReal, fValue.m_fReal ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpGE( AESimdFloat32ConstRef fValue ) const
{
	return AEVector4fComparison::Convert( _mm_cmpge_ps( m_fReal, fValue.m_fReal ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpE( AESimdFloat32ConstRef fValue ) const
{
	return AEVector4fComparison::Convert( _mm_cmpeq_ps( m_fReal, fValue.m_fReal ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpNE( AESimdFloat32ConstRef fValue ) const
{
	return AEVector4fComparison::Convert( _mm_cmpneq_ps( m_fReal, fValue.m_fReal ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpLessZero( void ) const
{
	return AEVector4fComparison::Convert( _mm_cmplt_ps( m_fReal, _mm_setzero_ps() ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpLessEqualZero( void ) const
{
	return AEVector4fComparison::Convert( _mm_cmple_ps( m_fReal, _mm_setzero_ps() ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpGreaterZero( void ) const
{
	return AEVector4fComparison::Convert( _mm_cmpgt_ps( m_fReal, _mm_setzero_ps() ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpGreaterEqualZero( void ) const
{
	return AEVector4fComparison::Convert( _mm_cmpge_ps( m_fReal, _mm_setzero_ps() ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpEqualZero( void ) const
{
	return AEVector4fComparison::Convert( _mm_cmpeq_ps( m_fReal, _mm_setzero_ps() ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::CmpNotEqualZero( void ) const
{
	return AEVector4fComparison::Convert( _mm_cmpneq_ps( m_fReal, _mm_setzero_ps() ) );
}

AE_FORCEINLINE void AESimdFloat32::ZeroIfFalse( AEVector4fConstRefCompParam vcCompareMask )
{
	AEASSERT_MSG( vcCompareMask.AllAreSet() || ( vcCompareMask.GetMask() == AEVector4ComparisonMask::MASK_NONE ), "illegal compare mask" );
	m_fReal = _mm_and_ps( vcCompareMask.m_mMask, m_fReal );
}

AE_FORCEINLINE void AESimdFloat32::ZeroIfTrue( AEVector4fConstRefCompParam vcCompareMask )
{
	AEASSERT_MSG( vcCompareMask.AllAreSet() || ( vcCompareMask.GetMask() == AEVector4ComparisonMask::MASK_NONE ), "illegal compare mask" );
	m_fReal = _mm_andnot_ps( vcCompareMask.m_mMask, m_fReal );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D>
	struct unrollf_setDiv
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_IGNORE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: fSelf = _mm_mul_ps( fParam1.m_fReal, AEMath::QuadReciprocal( fParam2.m_fReal ) ); break;
				case AE_ACC_12_BIT: fSelf = _mm_mul_ps( fParam1.m_fReal, _mm_rcp_ps( fParam2.m_fReal ) ); break;
				default:			fSelf = _mm_div_ps( fParam1.m_fReal, fParam2.m_fReal ); break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_ZERO>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			const AESingleFloat32 equalsZero = _mm_cmpeq_ps( fParam2.m_fReal, _mm_setzero_ps() );
			AESingleFloat32 e;
			unrollf_setDiv<A, AE_DIV_IGNORE>::Apply( e, fParam1, fParam2 );
			fSelf = _mm_andnot_ps( equalsZero, e );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_HIGH>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			const AESingleFloat32 equalsZero = _mm_cmpeq_ps( fParam2.m_fReal, _mm_setzero_ps() );
			AESingleFloat32 e;
			unrollf_setDiv<A, AE_DIV_IGNORE>::Apply( e, fParam1, fParam2 );
			AESingleFloat32 huge = _mm_set1_ps( AE_FLOAT_HIGH );
			const __m128i mask = _mm_slli_epi32( _mm_srli_epi32( _mm_castps_si128( fParam1.m_fReal ), 31 ), 31 );
			huge = _mm_xor_ps( huge, _mm_castsi128_ps( mask ) );
		
			#if AE_SSE_VERSION >= 0x41
				fSelf = _mm_blendv_ps( e, huge, equalsZero );
			#else
				fSelf = _mm_or_ps( _mm_and_ps( equalsZero, huge ), _mm_andnot_ps( equalsZero, e ) );
			#endif
		}
	};

	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_MAX>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			const AESingleFloat32 equalsZero = _mm_cmpeq_ps( fParam2.m_fReal, _mm_setzero_ps() );
			AESingleFloat32 e;
			unrollf_setDiv<A, AE_DIV_IGNORE>::Apply( e, fParam1, fParam2 );
			AESingleFloat32 huge = _mm_set1_ps( AE_FLOAT_MAX );
			const __m128i mask = _mm_slli_epi32( _mm_srli_epi32( _mm_castps_si128( fParam1.m_fReal ), 31 ), 31 );
			huge = _mm_xor_ps( huge, _mm_castsi128_ps( mask ) );
			#if AE_SSE_VERSION >= 0x41
				fSelf = _mm_blendv_ps( e, huge, equalsZero );
			#else
				fSelf = _mm_or_ps( _mm_and_ps( equalsZero, huge ), _mm_andnot_ps( equalsZero, e ) );
			#endif
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setDiv<A, AE_DIV_SET_ZERO_AND_ONE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
		{
			unrollf_setDiv<A, AE_DIV_SET_ZERO>::Apply( fSelf, fParam1, fParam2 );
			const AESingleFloat32 one = g_vectorfConstants[AE_QUADREAL_1];
			const AESingleFloat32 absVal = AEMath::QuadFabs( _mm_sub_ps( fSelf, one ) );
			const AESingleFloat32 lessEqualEps = _mm_cmple_ps( absVal, g_vectorfConstants[AE_QUADREAL_EPS] );
		#if AE_SSE_VERSION >= 0x41
			fSelf = _mm_blendv_ps( fSelf, one, lessEqualEps );
		#else
			fSelf = _mm_or_ps( _mm_and_ps( lessEqualEps, one ), _mm_andnot_ps( lessEqualEps, fSelf ) );
		#endif
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathDivByZeroMode D> 
AE_FORCEINLINE void AESimdFloat32::SetDiv( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	AESimdReal_AdvancedInterface::unrollf_setDiv<A,D>::Apply( m_fReal, fParam1, fParam2 );
}

AE_FORCEINLINE void AESimdFloat32::SetDiv( AESimdFloat32ConstRef fParam1, AESimdFloat32ConstRef fParam2 )
{
	AESimdReal_AdvancedInterface::unrollf_setDiv<AE_ACC_23_BIT,AE_DIV_IGNORE>::Apply( m_fReal, fParam1, fParam2 );
}

template <AEMathAccuracyMode A, AEMathDivByZeroMode D> 
AE_FORCEINLINE void AESimdFloat32::Div( AESimdFloat32ConstRef fParam )
{
	SetDiv<A,D>( *this, fParam );
}

AE_FORCEINLINE void AESimdFloat32::Div( AESimdFloat32ConstRef fParam )
{
	SetDiv( *this, fParam );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::SignBitSet( void ) const
{
	return AEVector4fComparison::Convert( _mm_castsi128_ps( _mm_srai_epi32( _mm_castps_si128( m_fReal ), 31 ) ) );
}

AE_FORCEINLINE const AEVector4fComparison AESimdFloat32::SignBitClear( void ) const
{
	return AEVector4fComparison::Convert( _mm_castsi128_ps( _mm_cmpeq_epi32( _mm_srai_epi32( _mm_castps_si128( m_fReal ), 31 ), _mm_setzero_si128() ) ) );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathNegSqrtMode S>
	struct unrollf_sqrtInverse
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
			return _mm_setzero_ps();
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrtInverse<A, AE_SQRT_IGNORE>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply( AESimdFloat32ConstRef fSelf )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: return AEMath::QuadReciprocalSquareRoot( fSelf.m_fReal ); break;
				case AE_ACC_12_BIT: return _mm_rsqrt_ps( fSelf.m_fReal ); break;
				default:			return _mm_div_ps( g_vectorfConstants[AE_QUADREAL_1], _mm_sqrt_ps( fSelf.m_fReal ) ); break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_sqrtInverse<A, AE_SQRT_SET_ZERO>
	{
		AE_FORCEINLINE static AESingleFloat32 Apply(AESimdFloat32ConstRef fSelf )
		{
			const AESingleFloat32 equalsZero = _mm_cmple_ps( fSelf.m_fReal, _mm_setzero_ps() );
			const AESingleFloat32 e = unrollf_sqrtInverse<A, AE_SQRT_IGNORE>::Apply( fSelf );
			return _mm_andnot_ps( equalsZero, e );
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathNegSqrtMode S> 
AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::SqrtInverse( void ) const
{
	return AESimdFloat32::Convert( AESimdReal_AdvancedInterface::unrollf_sqrtInverse<A,S>::Apply( *this ) );
}

AE_FORCEINLINE const AESimdFloat32 AESimdFloat32::SqrtInverse( void ) const
{
	return AESimdFloat32::Convert(AESimdReal_AdvancedInterface::unrollf_sqrtInverse<AE_ACC_23_BIT, AE_SQRT_SET_ZERO>::Apply( *this ) );
}

namespace AESimdReal_AdvancedInterface
{
	template <AEMathAccuracyMode A, AEMathDivByZeroMode D>
	struct unrollf_setReciprocal
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			AE_SIMDFLOAT_TEMPLATE_CONFIG_NOT_IMPLEMENTED;
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_IGNORE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			switch (A)
			{
				case AE_ACC_23_BIT: fSelf = AEMath::QuadReciprocal( fValue.m_fReal ); break;
				case AE_ACC_12_BIT: fSelf = _mm_rcp_ps( fValue.m_fReal ); break;
				default:         fSelf = _mm_div_ps( g_vectorfConstants[AE_QUADREAL_1], fValue.m_fReal ); break;
			}
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_ZERO>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			const AESingleFloat32 equalsZero = _mm_cmpeq_ps( fValue.m_fReal, _mm_setzero_ps() );
			AESingleFloat32 e;
			unrollf_setReciprocal<A, AE_DIV_IGNORE>::Apply( e, fValue );
			fSelf = _mm_andnot_ps( equalsZero, e );
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_HIGH>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			const AESingleFloat32 equalsZero = _mm_cmpeq_ps( fValue.m_fReal, _mm_setzero_ps() );
			AESingleFloat32 e;
			unrollf_setReciprocal<A, AE_DIV_IGNORE>::Apply( e, fValue );
			AESingleFloat32 huge = _mm_set1_ps( AE_FLOAT_HIGH );
			const __m128i mask = _mm_slli_epi32( _mm_srli_epi32( _mm_castps_si128( fValue.m_fReal ), 31 ), 31 );
			huge = _mm_xor_ps( huge, _mm_castsi128_ps( mask ) );
			
			#if AE_SSE_VERSION >= 0x41
				fSelf = _mm_blendv_ps( e, huge, equalsZero );
			#else
				fSelf = _mm_or_ps( _mm_and_ps( equalsZero, huge ), _mm_andnot_ps( equalsZero, e ) );
			#endif
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_MAX>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			const AESingleFloat32 equalsZero = _mm_cmpeq_ps( fValue.m_fReal, _mm_setzero_ps() );
			AESingleFloat32 e;
			unrollf_setReciprocal<A, AE_DIV_IGNORE>::Apply( e, fValue );
			AESingleFloat32 huge = _mm_set1_ps( AE_FLOAT_MAX );
			const __m128i mask = _mm_slli_epi32( _mm_srli_epi32( _mm_castps_si128( fValue.m_fReal ), 31 ), 31 );
			huge = _mm_xor_ps( huge, _mm_castsi128_ps( mask ) );
		
			#if AE_SSE_VERSION >= 0x41
				fSelf = _mm_blendv_ps( e, huge, equalsZero );
			#else
				fSelf = _mm_or_ps( _mm_and_ps( equalsZero, huge ), _mm_andnot_ps( equalsZero, e ) );
			#endif
		}
	};
	
	template <AEMathAccuracyMode A>
	struct unrollf_setReciprocal<A, AE_DIV_SET_ZERO_AND_ONE>
	{
		AE_FORCEINLINE static void Apply( AESingleFloat32 &fSelf, AESimdFloat32ConstRef fValue )
		{
			unrollf_setReciprocal<A, AE_DIV_SET_ZERO>::Apply( fSelf, fValue );
			const AESingleFloat32 one = g_vectorfConstants[AE_QUADREAL_1];
			const AESingleFloat32 absVal = AEMath::QuadFabs( _mm_sub_ps( fSelf, one ) );
			const AESingleFloat32 lessEqualEps = _mm_cmple_ps( absVal, g_vectorfConstants[AE_QUADREAL_EPS] );
		
			#if AE_SSE_VERSION >= 0x41
				fSelf = _mm_blendv_ps( fSelf, one, lessEqualEps );
			#else
				fSelf = _mm_or_ps( _mm_and_ps( lessEqualEps, one ), _mm_andnot_ps( lessEqualEps, fSelf ) );
			#endif
		}
	};
} // End namespace 

template <AEMathAccuracyMode A, AEMathDivByZeroMode D> 
AE_FORCEINLINE void AESimdFloat32::SetReciprocal( AESimdFloat32ConstRef fValue )
{
	AESimdReal_AdvancedInterface::unrollf_setReciprocal<A,D>::Apply( m_fReal, fValue );
}

AE_FORCEINLINE void AESimdFloat32::SetReciprocal( AESimdFloat32ConstRef fValue )
{
	AESimdReal_AdvancedInterface::unrollf_setReciprocal<AE_ACC_23_BIT,AE_DIV_IGNORE>::Apply( m_fReal, fValue );
}

#endif // _AESIMDFLOAT32_SSE_INL_
